package com.soc.auth.security;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

@Slf4j
public class MyLoginAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    public MyLoginAuthenticationFilter() {
        // 以 "/user/login" 为登录接口
        super(new AntPathRequestMatcher("/user/login", "POST"));
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {

        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken;

        PhoneCaptchaAuthenticationToken phoneCaptchaAuthenticationToken;

        try (InputStream is = request.getInputStream()) {
            // 使用Jackson将JSON字符输入流转换为Java对象
            Map<String, Object> readValue = new ObjectMapper().readValue(is, Map.class);

            String loginMethod = (String) readValue.get("loginMethod");

            if ("usernamePassword".equals(loginMethod)) {
                String username = (String) readValue.get("username");
                String password = (String) readValue.get("password");
                usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(username, password);
                setDetails(request, usernamePasswordAuthenticationToken);

                return this.getAuthenticationManager().authenticate(usernamePasswordAuthenticationToken);
            } else if ("phoneCaptcha".equals(loginMethod)) {
                String phone = (String) readValue.get("phone");
                String captcha = (String) readValue.get("captcha");
                phoneCaptchaAuthenticationToken = new PhoneCaptchaAuthenticationToken(phone, captcha);
                setDetails(request, phoneCaptchaAuthenticationToken);

                return this.getAuthenticationManager().authenticate(phoneCaptchaAuthenticationToken);
            } else {
                throw new InternalAuthenticationServiceException("登录方式选择有问题");
            }
        } catch (IOException e) {
            // 让其抛出InternalAuthenticationServiceException异常能被AbstractAuthenticationProcessingFilter捕捉
            throw new InternalAuthenticationServiceException("解析请求的输入流出差");
        } catch (AuthenticationException e) {
            throw e;
        }
        catch (Exception e) {
            log.error(e.getMessage());
            // 让其抛出InternalAuthenticationServiceException异常能被AbstractAuthenticationProcessingFilter捕捉
            throw new InternalAuthenticationServiceException("系统内部出现问题");
        }
    }

    // 将 request 信息设置给 UsernamePasswordAuthenticationToken 的 details 属性
    protected void setDetails(HttpServletRequest request, AbstractAuthenticationToken authRequest) {
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
    }

}
